Skip to content

Casadesign - DRAFT DO NOT MERGE#7051

Draft
giacoelho wants to merge 116 commits into
mainfrom
casadesign
Draft

Casadesign - DRAFT DO NOT MERGE#7051
giacoelho wants to merge 116 commits into
mainfrom
casadesign

Conversation

@giacoelho

Copy link
Copy Markdown
Collaborator

This is a work in progress. Will flag when it is ready to merge.

gia and others added 12 commits July 9, 2026 17:49
Introduce Tailwind v4 alongside the existing Bootstrap stack so the UI can be
modernized page-by-page without breaking current views.

- Add tailwindcss + @tailwindcss/cli (v4), build:tailwind[:dev] npm scripts,
  and a `tw` process in Procfile.dev. Output lands in app/assets/builds, which
  Sprockets already serves via the manifest's link_directory.
- Add app/assets/stylesheets/tailwind.css: CSS-first design system (Inter font
  + an indigo "brand" palette) — the visual direction for the redesign.
- New Tailwind-only layout casa_auth.html.erb (split brand panel + form),
  used by both the user and all-casa sign-in controllers.
- Redesign devise/sessions/new.html.erb in a clean, modern Stripe/Airbnb style
  and wire up remember-me properly.

Scoped to sign-in only; every other page keeps the Bootstrap `application`
layout untouched. First step of an incremental migration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Approved font direction: swap the design-system typeface and the auth
layout's webfont link from Inter to Figtree (warmer humanist sans).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- design.md: living design-system doc (Tailwind v4 approach, Figtree type scale,
  color tokens, icon-tile pattern, component + empty-state specs, app-shell spec,
  migration checklist). Codifies the icon-tile treatment (icons on a soft colored
  background) for stat/status icons and reserves initial-avatars for people only.
- CLAUDE.md: point to design.md and record the casadesign commit/push-per-checkpoint
  workflow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New Tailwind-only layout: left sidebar with Pundit-guarded nav mirroring the
existing routes, plus a top bar (notifications, profile menu, sign out). Coexists
with the Bootstrap `application` layout — redesigned authenticated pages opt in via
`layout "casa_app"`. Icons via Bootstrap Icons CDN + Figtree (per design.md).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Supervisors now land on a real dashboard (DashboardController#show renders it in the
casa_app shell) instead of the Bootstrap volunteers table:

- SupervisorDashboard service builds per-volunteer follow-up status + summary stats
  from the supervisor's assigned volunteers.
- View: KPI cards, a "Needs your attention" list (icon-tile treatment per design
  feedback — replaces the ringed avatars), and a roster with color-coded
  contact-status pills.
- Empty states handled: no volunteers -> welcome + CTAs; nobody behind -> all
  caught up. The full volunteer management table remains at /volunteers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Feedback from design review:
- Avatar initials strip honorific prefixes (Mrs./Mr./…) and use first + last name
  only, via a shared `avatar_initials` helper (removed the duplicate in the service).
- Top-bar profile menu is triggered by the avatar alone; the name lives in the
  dropdown, not the trigger.
- Page header is the page name ("Dashboard") + <title>, not a greeting.

Accessibility (WCAG AA targets):
- Skip-to-content link, landmark labels, aria-labels on icon-only controls,
  aria-current on the active nav item, table scope + sr-only caption, visible
  focus rings, contrast bumps (slate-400 -> 500/600), role=status/alert on flash.

Responsive:
- Sidebar becomes an off-canvas drawer below lg with an accessible toggle
  (button + aria-expanded, Escape/backdrop to close) and a responsive grid/padding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Names now render as first + last only (no Mr./Mrs./...) wherever a person is shown
in the redesign — the shell sidebar/profile menu and the supervisor dashboard
(names and aria-labels), plus the avatar initials.

- New `NamePresentation.strip_honorific` + a `display_person(user)` view helper.
- Presentation-only: the stored `display_name` is left untouched. (An attempted
  `User#display_name` override was reverted — a security spec requires display_name
  to round-trip raw input unchanged, e.g. dangerous strings.)
- Documented in design.md + CLAUDE.md so it's applied on every page going forward.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The bottom-of-sidebar user block (avatar + name + role) duplicated the identity
already shown by the top-right avatar account menu, and was non-interactive. Drop
it; the top-right menu is the single source for identity + account actions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The "CV" placeholder brand mark wasn't a value-add at 36px (the org name already
identifies the chapter) and using the real org logo there would add image/variant
infrastructure for little gain. Show the org name alone in the sidebar header; the
full logo stays for contexts with room (sign-in, court reports). design.md updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bring the rest of the auth flow in line with the redesigned sign-in:
- Forgot password (passwords/new), reset password (passwords/edit), and
  accept-invitation (invitations/edit) rebuilt in Tailwind, matching the sign-in's
  inputs/buttons/error styling. CASA's email-or-phone reset is preserved.
- Users::PasswordsController uses `layout "casa_auth"`; the invitation-accept action
  renders in casa_auth (admin invite `new`/`create` untouched).
- casa_auth `<title>` is now driven by `content_for(:page_title)`; each page sets its
  own title (Sign in / Reset your password / Choose a new password / Accept your invitation).

Verified all three render 200 in the new layout (accept-invitation via a valid token).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Apply the honorific-free naming rule to the existing Bootstrap UI, not just the
redesign:
- 37 `.display_name` person-name sites across ~20 legacy views now render via the
  `formatted_name` helper (org names, form-value symbols, and the checkbox-id slug
  line were intentionally excluded).
- The 4 DataTables (volunteer, supervisor, case-contact, reimbursement) strip
  honorifics on their Ruby name outputs (display_name + supervisor_name); SQL
  select/order strings are untouched.
- Added a `formatted_name(name)` string helper alongside `display_person`, both
  backed by `NamePresentation`.

Verified /supervisors, /volunteers, /casa_cases render 200 with zero honorifics;
datatable classes load clean; standardrb + rendering green. Docs updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The header helper text becomes a short single sentence with no em-dash; the org
name already appears in the sidebar header, so it's no longer repeated here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added dependencies Touches dependency files javascript Touches JavaScript code ruby Touches Ruby code erb Touches ERB templates labels Jul 9, 2026
@giacoelho
giacoelho marked this pull request as draft July 9, 2026 23:01
gia and others added 3 commits July 10, 2026 15:34
DashboardController#show now renders the casadesign supervisor dashboard
(SupervisorDashboard + casa_app layout) for supervisors, but the request
spec still asserted the old redirect to the volunteers overview and was
failing on the branch. Assert the dashboard renders and lists an assigned
volunteer instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…app shell

First page-by-page migration off the legacy Bootstrap UI, following design.md.
The notifications page is linked straight from the new shell (top-bar bell +
account menu), so it was the most visible remaining Bootstrap seam.

- Render NotificationsController#index in the casa_app layout.
- Restyle the index, NotificationComponent, and patch-notes partial onto the
  design system: card list, leading icon tiles, unread dot, and a cold-start
  empty state. Switch Font Awesome (fas fa-*) to Bootstrap Icons (bi-*), which
  is the icon set actually loaded on Tailwind pages.
- Move the specs off Bootstrap-class selectors onto semantic data-* hooks
  (data-notification-list-item, data-read / data-unread-dot) without weakening
  behavior coverage. All notification/patch-note ordering, counts, and empty
  states remain asserted.

Verified: component, view, request (renders the full casa_app layout), and
system specs all pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… backlog

- design.md: reframe as the permanent source of truth to refer to for all UI
  work. Add a "Design decisions (rationale)" log capturing the why behind the
  system (Tailwind-alongside-Bootstrap, layout opt-in, indigo/slate, Figtree,
  bi-* icons, icon-tile-vs-avatar, org-name-only sidebar, presentation-only
  honorific stripping, triage dashboards, empty-state taxonomy, a11y bar,
  build/output), a repeatable "Migrating a page" playbook, and a migration
  status that points at the backlog.
- design-todo.md: new prioritized, phased backlog (the "what's left") for the
  page-by-page migration off Bootstrap, plus cross-cutting infra and known
  pre-existing debt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the 🧪 Tests Tests label Jul 10, 2026
gia and others added 6 commits July 10, 2026 15:54
Second app-shell leaf page (linked from the account menu). Rebuilds the whole
edit-profile screen on the design system while preserving every behavior.

- Render UsersController in the casa_app layout.
- Rewrite edit.html.erb into cards: details, account, security, communication
  preferences, plus the volunteer languages table — using the documented input,
  button, and checkbox patterns.
- Replace the Bootstrap collapse accordions (Change Password / Change Email)
  with a small `disclosure` Stimulus controller (real <button> trigger, toggles
  a hidden panel, syncs aria-expanded) instead of relying on Bootstrap JS.
- Add a reusable Tailwind `shared/_form_errors` partial (the legacy
  `shared/_error_messages` stays for Bootstrap pages); it keeps the
  `@custom_error_header` hook so "... this password change ..." still renders.
- Preserve all field labels, ids, and JS-hook classes
  (toggle-email/sms-notifications, save-preference, password-new/-confirmation,
  submit-password, current_password_email, toggle-sms-notification-event) so
  require_communication_preference.js and password_confirmation.js keep working.

Verified: users request spec + the full edit system spec pass (79 examples);
erb-lint, standardrb, and StandardJS clean; JS bundle builds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rofile done

Add the two components introduced by the edit-profile migration (the Tailwind
form-error summary and the disclosure/collapsible-panel pattern) to design.md,
and tick edit profile in both the design.md status and design-todo.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rd subtitle

- Add a role badge (current_role as a brand-tinted pill) to the casa_app account
  menu header, under name + email — the one place identity metadata lives, and a
  parity with the role line the legacy header used to show. Industry-standard
  placement for a multi-role internal tool (keeps the sidebar/top-bar chrome clean).
- Supervisor dashboard subtitle -> "Track volunteer progress at a glance."
- Document the role badge in design.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The person-badge icon added no signal, so remove it. Colour the pill by role
using the design system's non-semantic accent tints — Volunteer = sky (blue),
Supervisor = violet (purple), Casa Admin = amber — so roles read apart at a
glance; unknown roles fall back to slate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…pt WCAG AA

- Drop the shouty `uppercase` transform from all design-system labels (account
  details, dashboard + languages table headers, patch-note category, auth "or"
  divider); render them sentence case. Sentence-case isolated copy ("My
  languages", "Learning hours this year").
- Bump muted label text from slate-400 (fails AA) to slate-500/600 for contrast.
- Redesign the form-error summary (shared/_form_errors): a role="alert" card with
  a leading icon and a tidy bulleted list instead of the plain block; keeps the
  heading text + #error_explanation so specs and behavior are unchanged.
- design.md: add Sentence case + Accessibility (WCAG 2.1 AA) as standing
  conventions, and fix the muted-text token. design-todo: track the app-wide
  interactive-label sentence-case pass and a slate-400 contrast audit.

Interactive button/field labels shared across pages (Update Profile, Change
Password, field labels) are spec-coupled across users/volunteers/all-casa-admin
and a shared example, so they're deferred to a holistic pass (tracked).

Verified: 109 examples across the touched pages pass; erb-lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Per design feedback: one sentence, no bullets, dashboard-style icon tile.
- shared/_form_errors now renders "Unable to save: <messages via to_sentence>"
  inside a rose danger icon tile (bg-rose-100 text-rose-600, bi-exclamation-
  triangle) matching the dashboard, dropping the old heading + bulleted list.
- Update edit_spec assertions from the Rails "N errors prohibited this X from
  being saved:" text to "Unable to save".
- design.md: refresh the Form errors component note.

Verified: 79 users edit + request examples pass; erb-lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gia and others added 12 commits July 19, 2026 19:19
…p (Phase 5 batch 3)

Hearing-type form: name + Active? in a card, plus (once persisted) a Tailwind
checklist-items table (id checklist_items) with New List Item / Edit links and a
button_to Delete. The delete uses turbo_confirm only, not the Dialog
confirm-button, because a non-JS destroy spec drives "Delete" directly
(rack_test ignores turbo_confirm and submits).

checklist_items new/edit is a custom casa_app form (Category / Description /
Mandatory) nested under the hearing type, redirecting to the hearing-type edit
page. custom org links is a casa_app form (Display text / URL / Active?; Submit
label from the `action` local). All three controllers get layout "casa_app" +
@active_nav = "settings".

Dropped the title-wrapper/card-style Bootstrap markup, lni icons, and
shared/error_messages (now shared/form_errors).

57 system + view + request examples green; no page overflow (the checklist table
scrolls within its card on mobile, like the settings admin tables); standardrb +
erb_lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ch 4)

Mileage rates: casa_app settings index (date / amount / Active? / Edit, no
delete) + a date+currency+Active? form.

Placements (nested under a case): casa_app index whose per-row Delete is a
Dialog with a visible "Close" + button_to "Confirm", so the non-:js destroy
spec passes under rack_test (which can't match the header X's aria-label); a
date + chevron-select form and a fact-card show. The index/new view specs move
off the Bootstrap .modal / .primary-btn assertions.

Banners: casa_app #banners table (keeps td.min-width for the system spec) with
a shared/_confirm_button Delete, and a form with the rich-text content editor +
a live reveal warning (new reveal Stimulus controller) when another banner is
already active. Trix needed its stylesheet folded into the casa_app tailwind
bundle (@import "trix/dist/trix.css") — without it the toolbar was unstyled and
overflowed the page to ~900px on every width.

58 system + view + request examples green; chevron darkest-pixel 114; pages fit
375-1280 (tables + the Trix toolbar scroll within their own containers).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both nested court-date forms now render on the casa_app shell, sharing
court_dates/_fields (date + court-report-due-date + judge/hearing-type
chevron-selects) and the existing casa_app court-orders twin
(casa_cases/_court_orders, with siblings off + resource "court_date"), so the
court-order-form nested sub-form and its dialogs are shared with the case-edit
page rather than restyling the Bootstrap shared/_court_order_list.

The submit stays wrapped in .top-page-actions (system specs click "Create" /
"Update" within it). The show page is a Tailwind card that preserves the
<dt><h6>Label:</h6></dt><dd> structure the xpath view/system specs assert (the
Title-Case colons ride the deferred sentence-case sweep), and deletes a future
court date via UJS method: :delete + data-confirm (native window.confirm, the
proven casa_app pattern the volunteer deactivate uses), which the :js spec
drives with accept_alert.

Court-date view specs move off .primary-btn; the edit spec's court-order heading
assertion matches the twin's sentence-case text. 80 system + view + request
examples green; chevron darkest-pixel 114; pages fit 375-1280.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Bootstrap JS tabs become server-side link tabs keyed on ?import_type= (the
controller already reads @import_type); each tab keeps its id (a system spec
clicks "supervisor-tab") and "Import X" label, and only the active panel renders.
The CSV error becomes an inline alert instead of a Bootstrap modal.

The SMS opt-in step is now an inline amber panel that preserves id="smsOptIn",
the sms-opt-in-checkbox / sms-opt-in-continue-button ids, and the enable-on-check
script — so the global src/import.js (which enables the import button on
file-select and persists the CSV to localStorage so it survives the opt-in
reload, gated on #smsOptIn) keeps working unchanged. Import buttons keep their
disabled state + ids so import.js re-enables them.

21 system + request examples green; page fits 375-1280.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The emancipation checklist show page moves to the casa_app shell with every
AJAX/collapse hook from the global src/case_emancipation.js preserved verbatim:
the .emancipation-category h6 with data-is-open, its child .category-collapse-icon,
the immediately-adjacent .category-options sibling (the Toggler reads it via
.next()), the .emacipation-category-input-label-pair div (kept a div, not a
label, so it doesn't double-toggle the checkbox the JS flips), each .check-item
with its O#{id} / C#{category} inputs, and a #notifications element so the
Notifier — and thus the whole controller's DOM-ready binding — constructs.

The checklist index becomes a plain Tailwind table; dropping the
all-case-emancipations id makes the global src/emancipations.js DataTable no-op.

42 system + view + request examples green; pages fit 375-1280. This completes
the Phase 5 admin long-tail CRUD migration.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…se 6a)

Adds a dedicated Tailwind `all_casa_admin` layout (its own sidebar — CASA
organizations / Patch Notes / Edit Profile / Feature Flags / Pg Dashboard + Log
Out — a simplified top bar, the Ruby For Good / site-issue / SMS-terms footer,
and inline flash that keeps a .header-flash hook), set on the base
AllCasaAdminsController. Patch notes stays on the legacy `application` layout
until its own sub-batch.

Migrated the dashboard (org table), casa_orgs new/show (+ the metrics list), and
casa_admins new/edit/_form to Tailwind cards, tables, forms, and button_classes.
The profile edit's change-password panel now uses the disclosure Stimulus
controller (Tailwind hidden toggle) like the regular user edit-profile page,
keeping id="collapseOne"; its view + :js specs move off the Bootstrap
.collapse/.show classes to .hidden. shared/error_messages stays where specs lock
#error_explanation + the "N errors prohibited" wording.

89 all-CASA-admin examples green. The one remaining red (all_casa_admin_spec:14,
a casa_admin visiting "/" expecting /supervisors) is a pre-existing regular-app
routing failure that fails identically on the legacy views.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rebuilds all_casa_admins/sessions/new and passwords/new on the Tailwind
casa_auth split-screen shell to match the already-migrated devise/sessions/new,
replacing the leftover Bootstrap markup. Preserves the spec-locked bits: the
"All CASA Log In" heading, the Email/Password labels, the .actions wrapper around
"Log in", and the flash block (sign-out lands on this page with "Signed out
successfully").

13 all-CASA-admin session + password examples green; both pages fit 375-1280.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The patch-notes page is a jQuery clone-CRUD (src/all_casa_admin/patch_notes.js
reads the DOM by structure), so the index + _patch_note partial keep the exact
hooks — #patch-note-list's child order (title, the new-note item the JS clones,
then existing notes), each .card-body's direct children (textarea, two
.label-and-select selects, .patch-note-button-controls), and the
.button-edit/.button-delete hooks — restyled to Tailwind cards. Selects keep the
native arrow (the design-system chevron needs a wrapper the JS's
.children('select') can't tolerate).

Two wiring fixes were needed: the shell now also loads the separate
`all_casa_admin` JS bundle (its `tables` DataTable no-ops on the plain Tailwind
tables), and the page renders layouts/components/_notifier because the Notifier
appends into its `.messages` container. The JS's injected Edit/Delete/Save/Cancel
buttons move from Bootstrap + FontAwesome to the button_classes strings + bi-*
icons. Also restores the emancipation show page's notifier (it had the same bare
#notifications, silently dropping AJAX save feedback).

The all-CASA-admin authenticated area is now fully on the design-system shell.
23 patch_notes + 91 all-casa examples green (only the pre-existing
all_casa_admin_spec:14 red); page fits 375-1280.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
static#index (the layout-false marketing page) is rebuilt on the CASA design
system — compiled tailwind.css + Figtree + the brand palette, a brand-gradient
hero, feature cards, testimonials, org logos, and a contact section — replacing
the Tailwind CDN + Alpine + hand-mixed blue/green utilities.

Preserves the spec-locked bits: the #organizations section, the .org_logo
images, and the "CASA Organizations Powered by Our App" heading. Signed-in users
are still redirected away by the controller.

4 examples green; the page fits 375-1280 (the header's decorative blur is
clipped by overflow-hidden, like the casa_auth aside).

This completes Phase 6: the all-CASA-admin area (shell + org management + auth +
patch notes) and the public landing page are all on the design system.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 11 casa_org/edit settings tables (judges, languages, placement/
learning-hour types + topics, contact types/groups/topics, hearing types,
custom org links, sent emails) and the hearing-type checklist_items table
now render the design-system table twin: the `<table>` is `hidden md:block`
and a `md:hidden` list of compact `<dl>` cards serves phones, matching the
documented responsive pattern in design.md. Eliminates the horizontal
scroll-within-card the admin tables had on mobile.

- `<tr id>` and per-row `shared/_confirm_button` stay on the table only; the
  card omits the id (it's a `<dl>`, not a row) and a duplicate confirm_button
  is safe (each Dialog is scoped by its own modal controller, id nil).
- Card labels mirror the existing table headers verbatim so the Title Case
  sweep still covers table + card together in one pass.
- Emancipation-checklists index (2 columns, measured W360/375) keeps its
  plain table — it never scrolled.

Verified: casa_orgs edit view spec (have_table), casa_org + hearing_types +
contact_types system specs, and the resource request specs all green;
erb_lint clean; pages measured fitting at 375/414/768/1024/1280.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The completed Phase 6 section above already covers the all-CASA-admin
shell, Devise edges, and static pages, so the leftover unchecked stub
was duplicated and misleading.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The last Bootstrap table in the case area (feature flag :new_case_contact_table)
is now a server-rendered casa_app page, retiring its jQuery serverSide DataTable
— matching the cases-index reference.

- Server-side filtering reuses the existing CaseContact scopes the DataTable used
  (contact type as an IN-subquery so multi-type rows don't duplicate), plus ?sort=
  and Pagy. Filter is a `disclosure` panel that auto-submits (GET); the case picker
  is the reused `multiple-select` TomSelect (chevron darkest-pixel verified to match
  the single-selects).
- Rows expand (one `<tbody data-controller="disclosure">` per row) to their topic
  answers + notes; per-row actions are inline icon buttons + native Dialogs (delete
  confirm, set-reminder note) — no dropdown, which `overflow-x-auto` would clip.
- Dropped the DataTables column-visibility picker (design already rejected it for the
  cases index; the md:hidden card stack covers mobile).
- Reminders stay on the list: followups#create/#resolve now redirect_back_or_to
  (destroy already redirects to the referer). Added a `wrapper_class` passthrough to
  shared/_confirm_button for menu/inline reuse.
- Drops the id="case_contacts" hook so dashboard.js's defineCaseContactsTable no-ops;
  the now-dead datatable action + CaseContactDatatable + JS block are queued for cleanup.

38 request (incl. new server-side filter examples) + 22 system examples green; the
concern spec updated for the migrated controller. Documented the expandable-rows +
inline-actions pattern in design.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

scope = filter_case_contacts(policy_scope(current_organization.case_contacts))
.includes(:casa_case, :contact_types, :contact_topics, :followups, :creator, contact_topic_answers: :contact_topic)
order = Arel.sql("case_contacts.#{@sort} #{@direction} NULLS LAST, case_contacts.id DESC")
gia and others added 17 commits July 20, 2026 14:14
The migrated new-design page is server-rendered, so its jQuery serverSide
DataTable and JSON endpoint are unused. Removes them:

- `CaseContacts::CaseContactsNewDesignController#datatable` action + its
  `datatable_case_contacts_new_design` route.
- `CaseContactDatatable` (+ its spec) — no other consumer; the sibling
  Volunteer/Supervisor/Reimbursement datatables + ApplicationDatatable stay.
- The `defineCaseContactsTable` block in `dashboard.js` (its DataTable init,
  row handlers, `collectCaseContactFilters`, the `buildTopicPills` /
  `buildExpandedContent` helpers, and the now-unused `Swal` /
  `fireSwalFollowupAlert` imports) + its call site + export. Also drops the
  stale `table#case_contacts` branch from the notifier guard. The kept
  volunteers/supervisors/casaCases tables + `pageNotifier` are untouched.
- `dashboard.test.js` (entirely `defineCaseContactsTable`) and the
  `POST /datatable` request-spec block.

Verified: jest 129/129, standardjs + standardrb clean, esbuild build compiles,
new_design request 11/11 + system 22/22.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Auditing controllers off the casa_app/casa_auth/all_casa/metrics layouts surfaced
several reachable leaf pages never in the phase plan that are still on the Bootstrap
`application` layout (fund_requests#new, casa_admins, other_duties, notes#edit,
case_assignments#index, error pages) — they block deleting the Bootstrap layout, so
they're now a tracked section and the "resume here" pointer. Also closed the Font
Awesome sweep (0 fas fa-* left in casa_app views) and flipped the case-contacts index
item to done.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First of the Bootstrap-layout stragglers. Rebuilds the New Fund Request form on
`layout "casa_app"` (@active_nav = "cases", back-link to the case), reusing the
casa_cases/new form pattern: max-w-2xl card, a 2-col grid of the short fields +
full-width textareas, shared/form_errors, and a single bottom primary submit.

- Kept the field-label substrings the system spec fills by, and the * / **
  footnotes explaining the documentation/payee notes. Only submitter_email is
  required (model validation); prefills (email / youth / requested-by) now use
  `.presence || default` so user input persists on a validation re-render.
- Sentence-cased the feature copy per the design rule (h1 + page title, the
  "Submit fund request" button, the success flash, and the case-show More link),
  updating the two coupled spec assertions.

2 system + 11 request examples green; standardrb + erb_lint clean; no horizontal
overflow at 500 / 768 / 1280.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Second straggler batch. Rebuilds the CASA-admin roster on `layout "casa_app"`
as self-contained views mirroring the supervisors sibling (retiring the shared
Bootstrap casa_admins/_form):

- index: a bespoke Tailwind table (email + Edit, "Deactivated" tag) with the
  #admins spec hook on the wrapper div.
- new: a minimal casa_app form (email / display name / phone), invitation on save.
- edit: Profile form (email / display name / phone / DOB + monthly-report
  checkbox) + an Account facts panel + a Status section. Deactivate keeps the
  UJS data-confirm (native window.confirm) the :js spec drives via accept_confirm;
  Resend Invitation / Change to Supervisor stay UJS data-method links.

Kept the spec-locked legacy error format ("N errors prohibited this Casa admin
from being saved:" + #error_explanation) via a casa_app-styled casa_admins/_errors
partial. This retires casa_admins/_form and leaves shared/_edit_form +
shared/_invite_login without a consumer (queued in the dead-code cleanup list).
Spec-locked Title Case labels kept verbatim and queued for the sentence-case sweep.

53 casa_admins examples green (index/new/edit incl. :js + request); standardrb +
erb_lint clean; no horizontal overflow at 500 / 768 / 1280.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Third straggler batch. Rebuilds volunteer "other duties" logging on
`layout "casa_app"`:

- index: a bespoke Tailwind table grouped by volunteer (desktop table + a mobile
  card twin), keeping the volunteer-only "New Duty" link.
- new/edit: unchanged thin `render "form"` wrappers over a rebuilt casa_app
  `_form` — the Hour(s)/Minute(s) duration inputs are the Tailwind twin (like
  learning hours), and the controller's convert_duration_minutes still combines
  them into duration_minutes. Notes keeps `required` + the default
  #other_duty_notes id (a :js spec asserts the HTML5 validation message).

Swapped shared/error_messages for shared/form_errors (no spec locks the legacy
"N errors" format here). Spec-locked Title Case labels ("Other Duties", "New
Duty", "Editing Duty", "Occurred On", "Duty Duration", "Enter Notes") kept
verbatim and queued for the sentence-case sweep.

26 examples green (view + system + request); standardrb + erb_lint clean; no
horizontal overflow at 500 / 768 / 1280.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fourth straggler. Rebuilds the single volunteer-note edit form on
`layout "casa_app"` (@active_nav = "volunteers"): a max-w-2xl card with a
back-link to the volunteer edit page it's reached from. Note has no validations,
so update always redirects back — no failure re-render, no error partial needed.
Kept note[content] + the spec-locked "Update Note" button (queued for the sweep).

23 examples green (system + request); standardrb + erb_lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The straggler audit flagged case_assignments#index, but it isn't a page:
`resources :case_assignments, only: %i[create destroy]` defines no index route
or action, and the view referenced an @volunteer nothing assigns (it even used
the DataTable id='casa_cases'). The view could never render, so delete it rather
than migrate. case_assignments_path is only the create POST target, unaffected.

45 case_assignments request examples green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Last straggler. GET /error is a public dev/QA "Intentional error test" page
(ErrorController, authenticate_user! skipped; a button POSTs to #create which
raises a test exception) — not the 404/422/500 handler, which stays static
public/*.html.

Because it's viewable logged-out, it can't use the casa_app shell (which needs
current_user + the org sidebar). Added a minimal logged-out layouts/error.html.erb
(compiled tailwind + Figtree, no app JS) and rebuilt the page as a centered
Tailwind card. With this, every reachable straggler HTML page is off the Bootstrap
application layout.

2 request examples green (GET renders, POST raises); standardrb + erb_lint clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Recorded the audit result: with the stragglers migrated, no web controller
renders an HTML page on the `application` layout (remaining default-layout
controllers are data-only; the only application-layout .html.erb templates are
mailer views, which use the mailer layout). The decommission item is now
unblocked, with endgame steps + the caveat that application.js is still loaded
by casa_app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The casa_admins migration rebuilt the edit page (replacing the shared
invite_login partial with a casa_app Account section), but I ran only the
system + request specs, not the view spec. Update its assertions to the new
markup — same account facts (Added to system / Invitation email sent /
Invitation accepted / Last logged in / Password reset last sent), without the
old partial's exact whitespace. 3 examples green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With every page migrated, no web controller renders an HTML page on the
`application` layout: the remaining default-layout controllers are data-only
(CSV/XLSX reports, preference_sets, api/*, android_app_associations, AJAX
sub-resources with no .html.erb), and the only application-layout .html.erb
templates are mailer views (mailer layout). Devise's default controllers resolve
to layouts/devise, not application. Verified with the full request + view spec
sweep — the layout deletion introduces no new failures (view specs render without
a layout; the pre-existing reds fail identically at the pre-session base commit).

Left ApplicationController's layout implicit — an explicit `layout "casa_app"`
would be inherited by the logged-out `Devise::*` controllers and break them.

Not yet: `application.scss` stays — layouts/devise.html.erb (the live shell for
Devise's default confirmation/edge pages) still loads it. And application.js
stays — casa_app still loads it. Both tracked in design-todo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move Devise's last un-customized default controllers onto the casa_auth shell so
nothing renders on the Bootstrap layouts/devise anymore, then delete it plus
application.scss and the legacy icon CSS.

- New thin `layout "casa_auth"` subclasses, routed via devise_for:
  Users::ConfirmationsController (User is :confirmable), and
  AllCasaAdmins::PasswordsController + AllCasaAdmins::InvitationsController
  (devise_for :all_casa_admins had only customized sessions).
- Styled devise/confirmations/new (new) and rebuilt devise/invitations/new
  (Bootstrap -> casa_auth). This also fixes the all-CASA password/invitation
  pages, which had been rendering Tailwind views on the CSS-less Bootstrap devise
  shell (unstyled). devise/passwords/* and invitations/edit were already
  casa_auth-styled + resource-agnostic.
- Deleted layouts/devise.html.erb, app/assets/stylesheets/application.scss, and
  public/assets/css/{lineicons,materialdesignicons.min,main}.css.
- Rewired the build off Bootstrap SCSS: dropped build:css / build:css:dev
  (package.json) + the css: Procfile.dev process; pointed bin/setup, bin/update,
  and the assets git hook at build:tailwind.

application.js stays (casa_app + casa_auth still load it). Verified: all 6 devise
HTML pages render 200 on casa_auth; auth specs green; the full request+view sweep
adds no new failures (updated the invitations/new view spec for the new copy).
Orphaned Bootstrap SCSS partials + old sidebar/header partials are queued in
dead-code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The case-details cluster the backlog names first. casa_cases/show fact labels
(Transition Aged Youth / Youth's Date in Care / Next Court Date / Court Report
Status / No Court Dates), the "Next Court Date" label on casa_cases/new, the
"Transition aged youth" header/card on casa_cases/index, and the report headings
on reports/index (Want Driving Reimbursement / Contact Made / Transition Aged
Youth) -> sentence case. Canonical term is "Transition-aged youth" (the hyphenated
form most migrated pages already use). Updated the coupled system/view specs
(show/new/edit/additional_index/reports + show view spec) in lockstep, incl. the
new-case form's court-date fill_in (which had matched the old label by
case-sensitive substring). Data strings (CSV headers, model messages, mailer
text) left as-is. Specs green (bar the 2 pre-existing placement reds in the
show view spec).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
court_dates show/new/edit headings + fact labels + form controls -> sentence
case: "Court Date"/"New Court Date"/"Editing Court Date" headings; "Case Number:",
"Court Report Due Date:", "Hearing Type:", "Court Orders:" fact labels;
"Add Court Date"/"Add Court Report Due Date" form labels; "Delete Future Court
Date" and "Download Report (.docx)" buttons. "Judge:" left (single word). Updated
the coupled system + view specs. The DOCX court-report label (court_dates_spec)
is a separate generated artifact, left as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The shared edit-profile cluster across users/edit + all_casa_admins/edit +
all_casa_admins/casa_admins/edit: Update Profile, Change Password, New Password,
New Password Confirmation, Current Password, Update Password, Change Email, and
"Enable Twilio For Text Messaging" -> sentence case (Twilio kept as a proper
noun). Updated every coupled spec in lockstep (users/edit_spec, the all-CASA
password_change/edit/all_casa_admin specs, notifications index, the shared
phone-error example, and the all-CASA edit view spec), including the specs'
standalone "Password Confirmation" field locators that had matched the old label
by case-sensitive substring. Only pre-existing red is all_casa_admin_spec:14.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The per-page Title Case queued while migrating these pages this session:
- casa_admins: "Create New Casa Admin" -> "Create new CASA admin" (CASA kept as
  the acronym), "Receive Monthly Learning Hours Report", "Resend Invitation",
  "Change to Supervisor".
- other_duties: "Other Duties", "New Duty", "Editing Duty", "Occurred On",
  "Duty Duration", "Enter Notes".
- notes: "Update Note".
Coupled system + view specs updated in lockstep. (edit_spec:119 convert-to-
supervisor is a pre-existing :js flake — green in isolation.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Batches 1-4a done (case-detail labels, court dates, edit-profile shared labels,
casa_admins/other_duties/notes); remaining 4b-4d + cases-index CTAs enumerated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Touches dependency files erb Touches ERB templates javascript Touches JavaScript code ruby Touches Ruby code 🧪 Tests Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants